package com.wangdong.bitmapcache;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.webkit.DownloadListener;

import com.wangdong.bitmapcache.libcore.io.DiskLruCache;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 本地 缓存
 */
public class BitmapDiskCache {

    private DiskLruCache mDiskLruCache = null;

    //
    public BitmapDiskCache(Context context) {
        try {
            File cacheDir = getDiskCacheDir(context, "bitmap");
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 本地缓存路径
     * @param context   环境变量
     * @param uniqueName 文件名称
     * @return {File}
     */
    public File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath;
        /**
         * 判断SD卡是否挂载,和存在
         */
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
            //获取sd卡的缓存文件地址
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            //获取应用下缓存地址
            cachePath = context.getCacheDir().getPath();
        }
        /**
         * 在缓存文件下创建自定义命名的文件夹并返回File
         */
        return new File(cachePath + File.separator + uniqueName);
    }

    /**
     * 通过应用管理获取应用 版本code号
     * @param context
     * @return
     */
    public int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    //因为涉及下载，需要在线程中执行此方法
    public void downloadBitmapToDiskCache(String imageUrl, DownloadListener mDownloadListener) {
        try {
            String key = getMD5String(imageUrl);
            DiskLruCache.Editor editor = mDiskLruCache.edit(key);
            if (editor != null) {
                OutputStream outputStream = editor.newOutputStream(0);
                if (downloadUrlToStream(imageUrl, outputStream)) {
                    editor.commit();
                    if (mDownloadListener != null) {
                        Bitmap bmp = getBitmapFromDiskCache(imageUrl);
                        mDownloadListener.downloadSuccess(bmp);
                    }
                } else {
                    editor.abort();
                    if (mDownloadListener != null) {
                        mDownloadListener.downloadFail();
                    }
                }
            }
          mDiskLruCache.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * MD5加密
     * @param key
     * @return
     */
    public String getMD5String(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    /**
     *  字节 转 16进制 转 String
     * @param bytes
     * @return
     */
    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
        //系统版本高 HttpURLConnection 使用回报错 需要在清单文件中添加 android:usesCleartextTraffic="true"
        HttpURLConnection urlConnection = null;
        BufferedOutputStream out = null;
        BufferedInputStream in = null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream());
            out = new BufferedOutputStream(outputStream);
            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
            return true;
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 获取本地缓存中的图片
     * @param imageUrl 通过图片的url
     * @return
     */
    public Bitmap getBitmapFromDiskCache(String imageUrl) {
        try {
            String key = getMD5String(imageUrl);
            DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
            if (snapShot != null) {
                InputStream is = snapShot.getInputStream(0);
                Bitmap bitmap = BitmapFactory.decodeStream(is);
                return bitmap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 移除 指定的imageUrl的图片
     * @param imageUrl
     * @return
     */
    public boolean removeBitmapFromDiskCache(String imageUrl) {
        try {
            String key = getMD5String(imageUrl);
            return mDiskLruCache.remove(key);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 清空本地图片缓存
     */
    public void removeAll() {
        try {
            mDiskLruCache.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取本地缓存 图片个数
     */
    public void getAllSize() {
        mDiskLruCache.size();
    }

    public void flush() {
        try {
            mDiskLruCache.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void close() {
        try {
            mDiskLruCache.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public interface DownloadListener {
        public void downloadSuccess(Bitmap bitmap);
        public void downloadFail();
    }
}
